home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / scope / 001-025 / scopedisk3 / 68kasm / src / operands.c < prev    next >
C/C++ Source or Header  |  1995-03-18  |  16KB  |  535 lines

  1. /*------------------------------------------------------------------*/
  2. /*                                    */
  3. /*              MC68000 Cross Assembler                */
  4. /*                                    */
  5. /*          Copyright    (c) 1985 by Brian R. Anderson            */
  6. /*                                    */
  7. /*           Operand processor - October 14, 1987            */
  8. /*                                    */
  9. /*   This program may be copied    for personal, non-commercial use    */
  10. /*   only, provided that the above copyright notice is included        */
  11. /*   on    all copies of the source code.    Copying    for any    other use   */
  12. /*   without the consent of the    author is prohibited.            */
  13. /*                                    */
  14. /*------------------------------------------------------------------*/
  15. /*                                    */
  16. /*        Originally published (in Modula-2) in            */
  17. /*        Dr.    Dobb's Journal, April, May, and June 1986.          */
  18. /*                                    */
  19. /*    AmigaDOS conversion copyright (c) 1987 by Charlie Gibbs.    */
  20. /*                                    */
  21. /*------------------------------------------------------------------*/
  22.  
  23. #include <stdio.h>
  24. #include "a68kdef.h"
  25. #include "a68kglb.h"
  26.  
  27. /* Functions */
  28. extern int  LineParts(), GetField(), Instructions(), ObjDir();
  29. extern int  GetSize(), ReadSymTab(), OpenIncl();
  30. extern long AddrBndW(),    AddrBndL(), GetValue(),    CalcValue();
  31. extern char *malloc();
  32. extern FILE *fopen();
  33.  
  34. int GetArgs(), GetAReg(), GetInstModeSize(), GetMultReg();
  35.  
  36.  
  37.  
  38. int GetArgs (name) char    *name;
  39. /* Gets    macro arguments    and adds them to FNStack after adding "name".
  40.     Returns the    number of arguments added to the stack.
  41.     Note that this might not be    the full number    of arguments
  42.     provided if    the stack overflowed.                */
  43. {
  44.     register int i, j, narg, instring;
  45.     char currarg[MAXLINE];        /* Current argument */
  46.  
  47.     narg = 0;                /* Argument counter */
  48.  
  49.     Heap2Space (strlen (name) +    1);    /* Find    space for name */
  50.     strcpy (NextFNS, name);        /* Add name to stack */
  51.     NextFNS += strlen (name) + 1;    /* Bump    pointer    */
  52.     if (NextFNS    > High2)
  53.     High2 =    NextFNS;        /* Update high-water mark */
  54.  
  55.     i =    SrcLoc;                /* Now scan Line */
  56.     while ((Line[i] != ' ') && (Line[i] != ';') && (Line[i] != '\0')) {
  57.     j = 0;
  58.     if (instring = (Line[i]    == '<'))    /* String delimiter */
  59.         i++;
  60.     while (1) {
  61.         if (instring) {
  62.         if (Line[i] == '>') {
  63.             i++;
  64.             break;            /* End of string */
  65.         }
  66.         } else {
  67.         if (Line[i] == '\0') break;     /* End of line */
  68.         if (Line[i] == ',') break;      /* End of operand */
  69.         if (Line[i] == ' ') break;      /* End of all operands */
  70.         if (Line[i] == ';') break;      /* Start of comments */
  71.         }
  72.         currarg[j++] = Line[i++];        /* Get a character */
  73.     }
  74.     currarg[j] = '\0';
  75.     Heap2Space (j +    1);            /* Check for space */
  76.     strcpy (NextFNS, currarg);        /* Store argument */
  77.     NextFNS    += strlen (currarg) + 1;    /* Next    available space    */
  78.     if (NextFNS > High2)
  79.         High2 = NextFNS;            /* High-water mark */
  80.     narg++;                    /* Count arguments */
  81.     if (Line[i] == ',')
  82.         i++;            /* Skip    over separator */
  83.     }
  84.     return (narg);            /* Successful completion */
  85. }
  86.  
  87.  
  88.  
  89. EffAdr (EA, Bad) struct    OpConfig *EA; int Bad;
  90. /* Adds    effective address field    to Op (BITSET representing opcode) */
  91. {
  92.     if ((1 << (EA->Mode    - 1)) IN Bad) {
  93.     Error (EA->Loc,    ModeErr);    /* Invalid mode    */
  94.     return;
  95.     } else if (EA->Mode    > 12)        /* Special modes */
  96.     return;
  97.     else if (EA->Mode <    8)        /* Register direct or indirect */
  98.     Op |= ((EA->Mode - 1) << 3) | EA->Rn;
  99.     else
  100.     Op |= 0x0038 | (EA->Mode - 8);    /* Absolute modes */
  101.     OperExt (EA);
  102. }
  103.  
  104.  
  105.  
  106. OperExt    (EA) struct OpConfig *EA;
  107. /* Calculate operand Extension word, and check range of    operands */
  108. {
  109.     switch (EA->Mode) {
  110.     case AbsL:
  111.         break;   /*    No range checking needed */
  112.     case AbsW:
  113.     case ARDisp:
  114.     case PCDisp:
  115.         if ((EA->Value < -32768) ||    (EA->Value > 32767))
  116.         Error (EA->Loc,    SizeErr);
  117.         break;
  118.     case ARDisX:
  119.     case PCDisX:
  120.         if ((EA->Value < -128) || (EA->Value > 127))
  121.         Error (EA->Loc,    SizeErr);
  122.         EA->Value &= 0x00FF;              /* Displacement */
  123.         EA->Value |= EA->Xn    << 12;            /* Index reg. */
  124.         if (EA->X == Areg)       EA->Value |=    0x8000;    /* Addr. Reg. */
  125.         if (EA->Xsize == Long) EA->Value |=    0x0800;    /* Long    reg.  */
  126.         break;
  127.     case Imm:
  128.         if (Size ==    Word) {
  129.         if ((EA->Value < -32768) || (EA->Value > 65535L))
  130.             Error (EA->Loc, SizeErr);
  131.         } else if (Size == Byte)
  132.         if ((EA->Value < -128) || (EA->Value > 255))
  133.             Error (EA->Loc, SizeErr);
  134.         break;
  135.     }
  136. }
  137.  
  138.  
  139.  
  140. GetOperand (oper, op, pcconv) char oper[]; struct OpConfig *op;    int pcconv;
  141. /* Finds mode and value    for source or destination operand.
  142.     If PC-relative addressing is permitted, "pcconv" gives the
  143.     offset to the displacement word; otherwise "pcconv" is zero. */
  144. {
  145.     register char ch;
  146.     register int  i, j;
  147.     char UCoper[MAXLINE], tempop[MAXLINE];
  148.     int     rloc, MultFlag, opend;
  149.     long templong;
  150.  
  151.     op->Value =    op->Defn = 0;
  152.     op->Mode = Null;
  153.     op->X    = X0;
  154.     op->Hunk = ABSHUNK;
  155.  
  156.     if ((opend = strlen    (oper) - 1) < 0)
  157.     return;                /* Nothing to process */
  158.  
  159.     for    (i = 0;    i <= opend; i++)
  160.     UCoper[i] = toupper (oper[i]);    /* Upper-case version */
  161.     UCoper[i] =    '\0';
  162.  
  163.     if (oper[0]    == '#') {               /* Immediate */
  164.     strcpy (oper, &oper[1]);
  165.     op->Value = GetValue (oper, op->Loc);
  166.     op->Mode  = Imm;
  167.     op->Hunk  = Hunk2;
  168.     op->Defn  = DefLine2;
  169.     return;
  170.     }
  171.  
  172.     i =    IsRegister (oper, opend+1);
  173.     if (i >= 0)    {
  174.     op->Mode = (i &    8) ? ARDir : DReg;    /* Register type */
  175.     op->Rn = i & 7;                /* Register number */
  176.     return;
  177.     } else if (i == -2)    {
  178.     op->Mode = MultiM;            /* Equated register list */
  179.     op->Value = Sym->Val;
  180.     return;
  181.     } else if (strcmp (UCoper, "SP") == 0) {
  182.     op->Mode = ARDir;            /* Stack Pointer */
  183.     op->Rn = 7;                /* (it's A7) */
  184.     return;
  185.     } else if (strcmp (UCoper, "SR") == 0) {
  186.     op->Mode = SR;                /* Status Register */
  187.     return;
  188.     } else if (strcmp (UCoper, "CCR") == 0) {
  189.     op->Mode = CCR;            /* Condition Code Register */
  190.     return;
  191.     } else if (strcmp (UCoper, "USP") == 0) {
  192.     op->Mode = USP;            /* User    Stack Pointer */
  193.     return;
  194.  
  195.     } else if ((oper[0]    == '(') && (oper[opend] == ')')) {
  196.     i = IsRegister (&oper[1], opend-1);
  197.     if (i >= 8 && i    <= 15) {
  198.         op->Mode = ARInd;        /* Address Register indirect */
  199.         op->Rn = i - 8;
  200.         return;
  201.     } else if (i > 0) {
  202.         Error (op->Loc, AddrErr);    /* Data    register is invalid */
  203.         return;
  204.     }    /* else    may be parenthesized expression    */
  205.  
  206.     } else if ((oper[0]    == '(')         /* Post-increment */
  207.     && (oper[opend-1] == ')')
  208.     && (oper[opend] == '+')) {
  209.     op->Mode = ARPost;
  210.     op->Rn = GetAReg (&oper[1], opend-2, op->Loc + 1);
  211.     return;
  212.  
  213.     } else if ((oper[0]    == '-')         /* Pre-decrement */
  214.     && (oper[1]    == '(')
  215.     && (oper[opend] == ')')) {
  216.     i = IsRegister (&oper[2], opend-2);
  217.     if (i >= 8 && i    <= 15) {
  218.         op->Mode = ARPre;
  219.         op->Rn = i - 8;
  220.         return;
  221.     } else if (i > 0) {
  222.         Error (op->Loc, AddrErr);    /* Data    register is invalid */
  223.         return;
  224.     }    /* else    parenthesized expression with leading minus? */
  225.     }
  226.  
  227.     /* Try to split off    displacement (if present).
  228.     We'll assume we have a register expression if the operand
  229.     ends with a parenthesized expression not preceded by an
  230.     operator.  I know this code is a real kludge, but that's
  231.     the result of the bloody syntax.  Thanks, Motorola.    */
  232.  
  233.     j =    strlen(oper) - 1;        /* Last    character */
  234.     if (i = (oper[j] ==    ')'))           /* Trailing parenthesis? */
  235.     while (oper[--j] != '(')        /* Find left parenthesis */
  236.         if (j <= 0)
  237.         break;
  238.     if (j <= 0)                /* Must    not be at beginning */
  239.     i = FALSE;
  240.     if (i) {
  241.     if (j == 1) {
  242.         if (oper[0]    == '-')
  243.         i = FALSE;        /* Leading minus sign */
  244.     } else {
  245.         if (oper[j-1] == '*') {     /* Location counter? */
  246.         if (!IsOperator    (&oper[j-2]) ||    (oper[j-2] == ')'))
  247.             i =    FALSE;        /* No, it's multiplication */
  248.         } else if (IsOperator (&oper[j-1]) && (oper[j-1] !=    ')')) {
  249.         i = FALSE;        /* Preceded by an operator */
  250.         }
  251.     }
  252.     }
  253.  
  254.     if (i) {        /* Looks like a    displacement mode */
  255.     oper[j]    = '\0';
  256.     op->Value = GetValue (oper, op->Loc);    /* Displacement    */
  257.     op->Hunk  = Hunk2;            /* Hunk    number */
  258.     op->Defn  = DefLine2;            /* Line    where defined */
  259.     oper[j++] = '(';                        /* Restore parenthesis */
  260.  
  261.     rloc = op->Loc + j;        /* The register    starts here */
  262.     j = GetField (oper, j, tempop);    /* Get address register    */
  263.     if (oper[j] == '\0')            /* If there's no index register */
  264.         tempop[strlen(tempop)-1] = '\0';    /* chop parenthesis */
  265.  
  266.     if ((tempop[2] == '\0')
  267.     && (toupper (tempop[0])    == 'P')
  268.     && (toupper (tempop[1])    == 'C')) {
  269.         op->Mode = PCDisp;            /* Program Counter */
  270.         if (op->Hunk == CurrHunk) {
  271.         op->Value -= (AddrCnt+pcconv);    /* Adjust displacement */
  272.         op->Hunk = ABSHUNK;
  273.         }
  274.     } else {
  275.         op->Mode = ARDisp;            /* Address Register */
  276.         op->Rn = GetAReg (tempop, strlen (tempop), rloc);
  277.     }
  278.     if (oper[j] != '\0') {          /* Index register is present */
  279.         if (op->Mode == PCDisp)
  280.         op->Mode = PCDisX;    /* Program Counter indexed */
  281.         else
  282.         op->Mode = ARDisX;    /* Address Register indexed */
  283.         if (oper[j]    != ',')
  284.         Error (op->Loc,    AddrErr);    /* Bad separator */
  285.         j++;                /* Skip    separator */
  286.         rloc = op->Loc + j;            /* Start of index */
  287.         j =    GetField (oper,    j, tempop);    /* Get index register */
  288.         if (oper[j]    == '\0')
  289.         tempop[strlen(tempop)-1]='\0';  /* Chop parenthesis */
  290.         else
  291.         Error (rloc, AddrErr);        /* It better be    there */
  292.  
  293.         op->Xsize =    GetSize    (tempop);    /* Index register size */
  294.         if (op->Xsize == Byte) {
  295.         Error (op->Loc+j-1, SizeErr);    /* Must    not be byte */
  296.         op->Xsize = Word;        /* Make    it word    for now    */
  297.         }
  298.         i =    IsRegister (tempop, strlen (tempop));    /* Get register    */
  299.         op->Xn = i & 7;            /* Index register number */
  300.         if ((i >= 0) && (i <= 7))
  301.         op->X =    Dreg;            /* Data    Register */
  302.         else if ((i    >= 8) && (i <= 15))
  303.         op->X =    Areg;            /* Address Register */
  304.         else
  305.         Error (rloc, AddrErr);        /* Invalid register */
  306.     }
  307.  
  308.     if ((op->Hunk >= 0) && (op->Hunk != ABSHUNK))
  309.         Error (op->Loc, RelErr);    /*  Relocatable    displacement */
  310.     return;
  311.     }
  312.  
  313.     /* Check to    see whether this could be a register list for MOVEM. */
  314.     i =    0;
  315.     MultFlag = FALSE;
  316.     while(1) {
  317.     if ((ch    = UCoper[i++]) == '\0') {
  318.         MultFlag = FALSE;
  319.         break;
  320.     }
  321.     if ((ch    == 'A') || (ch == 'D')) {
  322.         ch = UCoper[i++];
  323.         if (ch == '\0') {
  324.         MultFlag = FALSE;
  325.         break;
  326.         }
  327.         if ((ch >= '0') && (ch <= '7')) {
  328.         ch = UCoper[i++];
  329.         if (ch == '\0')
  330.             break;
  331.         if ((ch    == '/') || (ch == '-'))
  332.             MultFlag = TRUE;
  333.         } else {
  334.         MultFlag = FALSE;
  335.         break;
  336.         }
  337.     } else {
  338.         MultFlag = FALSE;
  339.         break;
  340.     }
  341.     }
  342.     if (MultFlag) {
  343.     op->Mode = MultiM;
  344.     op->Value = 0;        /* We must still get the mask */
  345.     return;
  346.     }
  347.  
  348.     op->Value =    GetValue (oper,    op->Loc);    /* Assume absolute mode    */
  349.     op->Defn  =    DefLine2;
  350.     templong  =    op->Value - (AddrCnt + pcconv);    /* Possible PC displacement */
  351.     if ((Hunk2 == CurrHunk) && pcconv && (DefLine2 <= LineCount)
  352.     && (templong >= -32768) && (templong <= 32767)) {
  353.     op->Mode  = PCDisp;        /* Convert to PC relative mode */
  354.     op->Value = templong;        /* Adjust displacement */
  355.     op->Hunk  = ABSHUNK;
  356.     } else {
  357.     op->Hunk  = Hunk2;
  358.     if ((Hunk2 == ABSHUNK) && (DefLine2 <= LineCount)
  359.     && (op->Value >= -32768) && (op->Value <= 32767))
  360.         op->Mode = AbsW;        /* Fits    in a word */
  361.     else
  362.         op->Mode = AbsL;
  363.     }
  364. }
  365.  
  366.  
  367.  
  368. int GetAReg (op, len, loc) char    op[]; int len, loc;
  369. /* Validate an address register    specification.
  370.     Valid specifications are A0    through    A7 , SP, or an EQUR label.
  371.     The    address    register number    will be    returned if it is valid.
  372.     Otherwise, Error will be called, using "loc" for the error
  373.     location (this is its only use), and zero (A0) will    be returned. */
  374. {
  375.     register int i;
  376.  
  377.     i =    IsRegister (op,    len);        /* Get register    number */
  378.     if ((i >= 8) && (i <= 15))
  379.     return (i - 8);            /* Valid address register */
  380.     else {
  381.     Error (loc, AddrErr);        /* Not an address register */
  382.     return (0);            /* Set to A0 */
  383.     }
  384. }
  385.  
  386.  
  387.  
  388. int IsRegister (op, len) char op[]; int    len;
  389. /* Check whether the current operand is    an address or data register.
  390.     Valid specifications are D0    throuth    D7, A0 through A7, SP,
  391.     or any symbol equated to a register    with the EQUR directive.
  392.     Return values:
  393.     0 through 7 - data registers 0 through 7 respectively
  394.     8 through 15 - address registers 0 through 7 respectively
  395.     -1 - not a recognizable    register
  396.     -2 - Equated register list for MOVEM instruction (REG)    */
  397. {
  398.     char tempop[MAXLINE];
  399.     register char *s;
  400.     register int  i;
  401.  
  402.     if (len == 2) {        /* Two-character specification */
  403.     i = toupper (op[0]);
  404.     if ((i == 'S') && (toupper (op[1]) == 'P')) {
  405.         return (15);            /* Stack Pointer */
  406.     } else if ((op[1] >= '0') && (op[1] <= '7')) {
  407.         if (i == 'A') {
  408.         return (op[1] -    '0' + 8);   /* Address Register */
  409.         } else if (i == 'D') {
  410.         return (op[1] -    '0');       /* Data Register */
  411.         }
  412.     }
  413.     }
  414.     if (!GotEqur)            /* If we have no EQURs to check    */
  415.     return (-1);            /*  don't waste any time here.  */
  416.     for    (i = 0,    s = op;    i < len; i++) {
  417.     if (IsOperator (s))
  418.         return (-1);        /* It sure isn't a label */
  419.     tempop[i] = *s++;
  420.     }
  421.     tempop[i] =    '\0';
  422.     if (ReadSymTab (tempop)) {
  423.     if (Sym->Flags & 0x60) {
  424.         AddRef (LineCount);        /* Found a register or list */
  425.         return ((Sym->Flags    & 0x20)    ? (int)    Sym->Val : -2);
  426.     }
  427.     }
  428.     return (-1);            /* Not a recognizable register */
  429. }
  430.  
  431.  
  432.  
  433. int GetInstModeSize (Mode) int Mode;
  434. /* Determines the size for the various instruction modes. */
  435. {
  436.     switch (Mode) {
  437.     case ARDisp:
  438.     case ARDisX:
  439.     case PCDisp:
  440.     case PCDisX:
  441.     case AbsW:
  442.         return (2);
  443.     case AbsL:
  444.         return (4);
  445.     case MultiM:
  446.         return (0);        /* Accounted for by code generator */
  447.     case Imm:
  448.         if (Size ==    Long)
  449.         return (4);
  450.         else
  451.         return (2);
  452.     default:
  453.         return (0);
  454.     }
  455. }
  456.  
  457.  
  458.  
  459. int GetMultReg (oper, predec, loc) char    oper[];    int predec, loc;
  460. /* Builds a register mask for the MOVEM    instruction */
  461. {
  462.     register char ch;
  463.     register int  i, j;
  464.     int    T1, T2;        /* Temporary variables for registers */
  465.     int    Range;        /* We're processing a range of registers */
  466.     int    RegType;    /* Register type (0=data, 1=address, 2=none) */
  467.     int    MultExt;    /* The result is built here */
  468.  
  469.     MultExt = 0;
  470.     Range = FALSE;
  471.     RegType = 2;
  472.     i =    0;
  473.  
  474.     ch = toupper (oper[i]);
  475.     while (ch != '\0') {
  476.     if (ch == 'A') {
  477.         if (RegType    == 2)
  478.         RegType    = 1;        /* Address register */
  479.         else {
  480.         Error (loc, OperErr);
  481.         return(0);
  482.         }
  483.     } else if (ch == 'D') {
  484.         if (RegType    == 2)
  485.         RegType    = 0;        /* Data    register */
  486.         else {
  487.         Error (loc, OperErr);
  488.         return(0);
  489.         }
  490.     } else if ((ch >= '0') && (ch <= '7')) { /* Register number */
  491.         if (RegType    != 2) {
  492.         T2 = (RegType *    8) + (ch - '0');  /* Bit number */
  493.         if (predec)
  494.             T2 = 15 - T2;    /* Predecrement    reverses mask */
  495.         if (!Range) {
  496.             MultExt |= (1 << T2);    /* Single register */
  497.             T1 = T2;    /* Save    number in case it's a range */
  498.         } else {            /* Range of registers */
  499.             Range = FALSE;
  500.             if (T1 > T2) {
  501.             j = T1;        /* Swap    registers if backwards */
  502.             T1 = T2;
  503.             T2 = j;
  504.             }
  505.             for    (j = T1; j <= T2; j++)
  506.             MultExt    |= (1 << j);    /* Registers in    range */
  507.         }
  508.         } else {
  509.         Error (loc, OperErr);
  510.         return(0);
  511.         }
  512.     } else if (ch == '-') {         /* Range indicator */
  513.         if ((Range == FALSE) && (RegType !=    2) && (i > 0)) {
  514.         RegType    = 2;
  515.         Range =    TRUE;
  516.         } else {
  517.         Error (loc, OperErr);
  518.         return(0);
  519.         }
  520.     } else if (ch == '/') {         /* Separator */
  521.         if ((Range == FALSE) && (RegType !=    2) && (i > 0))
  522.         RegType    = 2;
  523.         else {
  524.         Error (loc, OperErr);
  525.         return(0);
  526.         }
  527.     } else {            /* Garbage */
  528.         Error (loc,    OperErr);
  529.         return(0);
  530.     }
  531.     ch = toupper (oper[++i]);
  532.     }
  533.     return(MultExt);
  534. }
  535.